#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import socket
import urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler
import mimetypes
import cgi
import html
import json
import shutil
from pathlib import Path
from datetime import datetime

# 配置项
PORT = 8000
UPLOAD_DIR = "uploads"

# 确保上传目录存在
os.makedirs(UPLOAD_DIR, exist_ok=True)

# 获取本机IP地址
def get_local_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return "127.0.0.1"

# HTML页面模板
HTML_TEMPLATE = """<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简易文件分享工具</title>
    <style>
        body {{
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            max-width: 900px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
            color: #333;
        }}
        h1 {{
            color: #2c3e50;
            text-align: center;
            margin-bottom: 30px;
        }}
        .container {{
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            padding: 20px;
            margin-bottom: 20px;
        }}
        .info {{
            background-color: #e1f5fe;
            padding: 10px;
            border-radius: 5px;
            margin-bottom: 20px;
            text-align: center;
        }}
        .file-list {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }}
        .file-list th, .file-list td {{
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }}
        .file-list th {{
            background-color: #f2f2f2;
            font-weight: bold;
        }}
        .file-list tr:hover {{
            background-color: #f9f9f9;
        }}
        .button {{
            display: inline-block;
            padding: 8px 15px;
            background-color: #4CAF50;
            color: white;
            text-decoration: none;
            border-radius: 4px;
            border: none;
            cursor: pointer;
            font-size: 14px;
            transition: background-color 0.3s;
        }}
        .delete-btn {{
            background-color: #f44336;
        }}
        .button:hover {{
            background-color: #45a049;
        }}
        .delete-btn:hover {{
            background-color: #d32f2f;
        }}
        .upload-form {{
            margin: 20px 0;
        }}
        .upload-form input[type="file"] {{
            margin-bottom: 10px;
        }}
        .no-files {{
            text-align: center;
            color: #666;
            font-style: italic;
            padding: 20px;
        }}
        footer {{
            text-align: center;
            margin-top: 30px;
            color: #777;
            font-size: 14px;
        }}
    </style>
</head>
<body>
    <h1>简易文件分享工具</h1>
    
    <div class="info">
        您的文件分享地址: http://{ip}:{port}
    </div>
    
    <div class="container">
        <h2>上传文件</h2>
        <form method="POST" enctype="multipart/form-data" class="upload-form">
            <input type="file" name="file" required>
            <button type="submit" class="button">上传</button>
        </form>
    </div>
    
    <div class="container">
        <h2>文件列表</h2>
        {file_list}
    </div>
    
    <footer>
        简易文件分享工具 &copy; {year}
    </footer>
    
    <script>
        function confirmDelete(filename) {{
            if (confirm('确定要删除文件 "' + filename + '" 吗?')) {{
                fetch('/delete?filename=' + encodeURIComponent(filename), {{
                    method: 'DELETE'
                }}).then(response => {{
                    if (response.ok) {{
                        window.location.reload();
                    }}
                }});
            }}
        }}
    </script>
</body>
</html>
"""

class FileServer(BaseHTTPRequestHandler):
    def do_GET(self):
        # 解析URL
        parsed_path = urllib.parse.urlparse(self.path)
        path = parsed_path.path
        
        # 处理根路径请求，显示主页
        if path == "/":
            self.send_response(200)
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            
            # 生成文件列表
            file_list_html = self.generate_file_list()
            
            # 生成完整页面
            local_ip = get_local_ip()
            html_content = HTML_TEMPLATE.format(
                ip=local_ip,
                port=PORT,
                file_list=file_list_html,
                year=datetime.now().year
            )
            
            self.wfile.write(html_content.encode("utf-8"))
            return
            
        # 处理文件下载请求
        elif path.startswith("/download/"):
            filename = urllib.parse.unquote(path[10:])
            file_path = os.path.join(UPLOAD_DIR, filename)
            
            if os.path.exists(file_path) and os.path.isfile(file_path):
                self.send_response(200)
                
                # 设置内容类型
                content_type, _ = mimetypes.guess_type(file_path)
                if content_type:
                    self.send_header("Content-type", content_type)
                else:
                    self.send_header("Content-type", "application/octet-stream")
                
                # 设置文件名和内容长度
                self.send_header("Content-Disposition", f'attachment; filename="{urllib.parse.quote(filename)}"')
                self.send_header("Content-Length", str(os.path.getsize(file_path)))
                self.end_headers()
                
                # 发送文件内容
                with open(file_path, "rb") as f:
                    shutil.copyfileobj(f, self.wfile)
            else:
                self.send_error(404, "File not found")
            return
            
        # 处理其他路径请求
        else:
            self.send_error(404, "Not found")
            return
    
    def do_POST(self):
        # 处理文件上传请求
        if self.path == "/":
            # 解析表单数据
            form = cgi.FieldStorage(
                fp=self.rfile,
                headers=self.headers,
                environ={'REQUEST_METHOD': 'POST',
                        'CONTENT_TYPE': self.headers['Content-Type']}
            )
            
            # 获取上传的文件
            if "file" in form:
                file_item = form["file"]
                
                # 确保是文件而不是表单字段
                if file_item.filename:
                    # 获取安全的文件名
                    filename = os.path.basename(file_item.filename)
                    file_path = os.path.join(UPLOAD_DIR, filename)
                    
                    # 保存文件
                    with open(file_path, "wb") as f:
                        f.write(file_item.file.read())
                    
                    # 重定向回主页
                    self.send_response(303)
                    self.send_header("Location", "/")
                    self.end_headers()
                    return
            
            # 如果没有上传文件，返回错误
            self.send_response(400)
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(b"No file uploaded")
            return
            
        # 处理其他POST请求
        else:
            self.send_error(404, "Not found")
            return
    
    def do_DELETE(self):
        # 处理文件删除请求
        parsed_path = urllib.parse.urlparse(self.path)
        
        if parsed_path.path == "/delete":
            # 获取要删除的文件名
            query = urllib.parse.parse_qs(parsed_path.query)
            if "filename" in query and query["filename"]:
                filename = query["filename"][0]
                file_path = os.path.join(UPLOAD_DIR, filename)
                
                # 检查文件是否存在并删除
                if os.path.exists(file_path) and os.path.isfile(file_path):
                    os.remove(file_path)
                    
                    # 返回成功
                    self.send_response(200)
                    self.send_header("Content-type", "application/json")
                    self.end_headers()
                    self.wfile.write(json.dumps({"success": True}).encode("utf-8"))
                    return
            
            # 返回错误
            self.send_response(400)
            self.send_header("Content-type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"success": False, "error": "Invalid request"}).encode("utf-8"))
            return
            
        # 处理其他DELETE请求
        else:
            self.send_error(404, "Not found")
            return
    
    def generate_file_list(self):
        """生成文件列表HTML"""
        files = []
        
        # 获取上传目录中的所有文件
        for filename in os.listdir(UPLOAD_DIR):
            file_path = os.path.join(UPLOAD_DIR, filename)
            if os.path.isfile(file_path):
                # 获取文件大小和修改时间
                size = os.path.getsize(file_path)
                modified = datetime.fromtimestamp(os.path.getmtime(file_path))
                
                # 格式化文件大小
                if size < 1024:
                    size_str = f"{size} B"
                elif size < 1024 * 1024:
                    size_str = f"{size / 1024:.1f} KB"
                elif size < 1024 * 1024 * 1024:
                    size_str = f"{size / (1024 * 1024):.1f} MB"
                else:
                    size_str = f"{size / (1024 * 1024 * 1024):.1f} GB"
                
                # 添加到文件列表
                files.append({
                    "name": filename,
                    "size": size_str,
                    "modified": modified.strftime("%Y-%m-%d %H:%M:%S")
                })
        
        # 如果没有文件，显示提示
        if not files:
            return '<div class="no-files">暂无文件</div>'
        
        # 生成文件列表表格
        file_list_html = """
        <table class="file-list">
            <thead>
                <tr>
                    <th>文件名</th>
                    <th>大小</th>
                    <th>修改时间</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
        """
        
        for file in files:
            escaped_name = html.escape(file["name"])
            encoded_name = urllib.parse.quote(file["name"])
            
            # 完全避免在f-string中使用反斜杠
            escaped_name_js = escaped_name.replace("'", "\\'")
            onclick_attr = 'onclick="confirmDelete(\'' + escaped_name_js + '\')"'
            
            file_list_html += f"""
            <tr>
                <td>{escaped_name}</td>
                <td>{file["size"]}</td>
                <td>{file["modified"]}</td>
                <td>
                    <a href="/download/{encoded_name}" class="button" download>下载</a>
                    <button class="button delete-btn" {onclick_attr}>删除</button>
                </td>
            </tr>
            """
        
        file_list_html += """
            </tbody>
        </table>
        """
        
        return file_list_html

def run_server():
    ip = get_local_ip()
    server_address = ('', PORT)
    httpd = HTTPServer(server_address, FileServer)
    print(f"文件分享服务器已启动，正在监听端口 {PORT}")
    print(f"您可以通过以下地址访问：")
    print(f"- 本机访问: http://localhost:{PORT}")
    print(f"- 局域网访问: http://{ip}:{PORT}")
    print("\n按 Ctrl+C 停止服务器...")
    httpd.serve_forever()

if __name__ == "__main__":
    run_server() 